package com.jdj.framework.core.spring.bean;

import com.jdj.framework.core.base.utils.ReflectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;

/**
 * 实现spring 的实体包装类
 * @author caijinbang
 * @date 2019-04-14 13:01
 */
public class BeanWrapper  extends BeanWrapperImpl {
    public BeanWrapper(Object object) {
        super(object);
    }

    public BeanWrapper(Class<?> clazz) {
        super(clazz);
    }

    /**
     * 获取bean 有对应set，get方法的属性字段
     * @return
     */
    public PropertyDescriptor[] getPropertyDescriptorsInDeclaringOrder() {
        PropertyDescriptor[] propertyDescriptors = super.getPropertyDescriptors();
        List<Method> methodsInDeclaringOrder = ReflectionUtils.getMethodsInDeclaringOrder(getWrappedClass());
        Set<PropertyDescriptor> resultPropertyDescriptors = new LinkedHashSet<PropertyDescriptor>();
        for (Method method : methodsInDeclaringOrder) {
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                if (method.equals(propertyDescriptor.getReadMethod())
                    || method.equals(propertyDescriptor.getWriteMethod())) {
                    resultPropertyDescriptors.add(propertyDescriptor);
                    break;
                }
            }
        }
        return resultPropertyDescriptors.toArray(new PropertyDescriptor[resultPropertyDescriptors.size()]);
    }

    /**
     * 获取bean 的其它方法（不是属性字段的set方法，get方法）
     * @return
     */
    public Method[] getPropertyDescriptorsNotInDeclaringOrder() {
        PropertyDescriptor[] propertyDescriptors = super.getPropertyDescriptors();
        List<Method> methodsInDeclaringOrder = ReflectionUtils.getMethodsInDeclaringOrder(getWrappedClass());
        //
        Set<Method> otherMethod = new LinkedHashSet<Method>();
        //判断是否是属性字段的 set或get方法
        boolean isSetMethodOrGetMethod = false;
        //
        for (Method method : methodsInDeclaringOrder) {
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                if (method.equals(propertyDescriptor.getReadMethod())
                    || method.equals(propertyDescriptor.getWriteMethod())) {
                    isSetMethodOrGetMethod = true;
                    break;
                }
            }
            //不是属性字段的 set或get方法
            if (!isSetMethodOrGetMethod) {
                otherMethod.add(method);
            }
            isSetMethodOrGetMethod = false;
        }
        return otherMethod.toArray(new Method[otherMethod.size()]);
    }

    public void copyPropertiesTo(Object destinationBean, List<String> propertyNames) {
        BeanWrapper destinationBeanWrapper = new BeanWrapper(destinationBean);
        for (String propertyName : propertyNames) {
            destinationBeanWrapper.setPropertyValue(propertyName, getPropertyValue(propertyName));
        }
    }

    public Object getPropertyValueRecursively(String propertyName) throws BeansException {
        int dotIndex = propertyName.indexOf(".");
        if (dotIndex == -1) {
            return getPropertyValue(propertyName);
        } else {
            Object propertyBean = getPropertyValue(propertyName.substring(0, dotIndex));
            if (propertyBean == null) {
                return null;
            } else {
                return new BeanWrapper(propertyBean).getPropertyValueRecursively(propertyName.substring(dotIndex + 1));
            }
        }
    }

    public Class<?> getPropertyTypeRecursively(String propertyName) throws BeansException {
        int dotIndex = propertyName.indexOf(".");
        if (dotIndex == -1) {
            return getPropertyType(propertyName);
        } else {
            Object propertyBean = getPropertyValue(propertyName.substring(0, dotIndex));
            if (propertyBean == null) {
                return null;
            } else {
                return new BeanWrapper(propertyBean).getPropertyTypeRecursively(propertyName.substring(dotIndex + 1));
            }
        }
    }
}
